
/**
 * 
 * 火星文计算
 * 题目描述

已知火星人使用的运算符为#、$，其与地球人的等价公式如下：

x#y = 4*x+3*y+2
x$y = 2*x+y+3
其中 x、y 是无符号整数
地球人公式按C语言规则计算
火星人公式中，#的优先级高于$，相同的运算符，按从左到右的顺序计算
现有一段火星人的字符串报文，请你来翻译并计算结果。

输入描述
火星人字符串表达式（结尾不带回车换行）

输入的字符串说明：  字符串为仅由无符号整数和操作符（#、$）组成的计算表达式。例如：

123#4$5#67$78
用例保证字符串中，操作数与操作符之间没有任何分隔符。  
用例保证操作数取值范围为32位无符号整数。  
保证输入以及计算结果不会出现整型溢出。  
保证输入的字符串为合法的求值报文，例如：123#4$5#67$78  
保证不会出现非法的求值报文，例如类似这样字符串：  

#4$5                                             //缺少操作数  

4$5#                                             //缺少操作数  

4#$5                                             //缺少操作数  

4 $5                                              //有空格  

3+4-5*6/7                                     //有其它操作符  

12345678987654321$54321       //32位整数计算溢出
输出描述
根据输入的火星人字符串输出计算结果（结尾不带回车换行）

用例
输入	7#6$5#12
输出	157
说明	7#6$5#12  
=(4*7+3*6+2)$5#12
=48$5#12
=48$(4*5+3*12+2)
=48$58
=2*48+58+3
=157 
 */

import java.util.Arrays;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
  * 
  题目解析
正则解法

这个题目保证不会出现非法的求值报文，因此输入字符串是严格的“数字+操作符+数字”这种格式，因此，很适合使用正则去匹配。

首先，我先用正则匹配出"操作数#操作数"，然后将其替换为计算后的值，然后字符串中就只剩$了，因此再将字符串按照$分割，从左到右，两两操作计算。

最终就得到了题解。

本题需要注意的是，当替换"操作数#操作数"，为其结果值时，只能进行首次匹配替换，不能多次匹配替换。

比如"4#3#4#3"，首先计算出4#3的值为27，这里替换只能将第一次出现的4#3替换为27，而不能将所有4#3替换为27，因为这两种替换的结果可能会不同，比如

只替换第一次匹配：27#4#3
全部匹配替换：27#27
的结果是不同的，而本题中#必须是从左到右计算。

这里不同语言的字符串首次匹配替换的API功能各有差异：

JS	replace	String.prototype.replace() - JavaScript | MDN (mozilla.org)
Java	replaceFirst	String (Java Platform SE 8 ) (oracle.com)
Python	replace	Python replace()方法 | 菜鸟教程 (runoob.com)
其中

JS字符串的replace只替换第一次匹配，符合要求。
Java的replce方法是替换所有匹配，而replaceFirst方法是替换第一次匹配
Python的replace方法是替换所有匹配，但是我们可以通过replace第三个参数来控制最大替换次数。
栈解法

由于C语言的正则操作十分繁琐，以及没有内置的字符串替换操作，因此C语言建议使用栈解法：

首先我们需要定义一个栈stack，用于记录操作数和操作符，
然后定义一个操作数容器operNum，由于收集操作数的数字字符，
接下来开始遍历输入字符串的每一个字符c：

如果 c 是数字，则收集进操作数容器operNum，如下图所示


如果 c 不是数字，即#或$，那么此时有两个信息：
我们完成了某个操作数所有字符的收集，比如



此时，我们应该检查stack是否为空，如果为空，则操作数直接入栈，然后清空操作数容器，方便接收下一个操作数。

之后将操作符入栈


如果stack不为空且stack栈顶是#，比如：



则此时我们应该进行#运算，即取出栈顶的#后，再取出栈顶元素作为操作数 x，而当前操作数缓存容器operNum中的数值也完成了收集，且可以当作操作数y，然后带入#运算公式。

#运算完成后，我们需要将运算结果重新压入栈中。并且需要清空operNum容器，以及将当前扫描的操作符入栈


之后继续走逻辑




如果扫描到运算符，则需要检查stack栈顶是否为#运算，若不是，则直接将operNum和当前扫描的操作符入栈

之后继续逻辑：



此时扫描到了输入字符串的尾部，并且operNum完成了最后一个操作数的收集。此时我们需要将最后一个操作数入栈，入栈前还需要检查栈顶是否为#，若是，则取出栈顶两个元素，按照前面逻辑进行#运算，





完成#运算后：

如果stack.size == 1，则栈中只剩下一个操作，此时可以直接当成结果返回。
如果stack.size > 1，则栈中至少有两个操作数以及一个$，接下里应该进行$运算逻辑：
首先我们应该从栈底取出一个元素作为x
之后循环逻辑：先取出栈底的操作符$，再取出栈底的操作数y，然后进行$运算，并将运算结果赋值给x，即运算结果作为新的操作数x，然后继续循环逻辑，直到stack为空时结束。
最后x中记录的值即为结果。

  */
public class 火星文计算 {
    
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        doZe(str);

        //doStack(str);

    }

    private static void doZe(String str){

        Pattern p = Pattern.compile("(\\d+)#(\\d+)");
 
        while (true) {
            Matcher m = p.matcher(str);
            if (!m.find()) break;
        
            String subStr = m.group(0);
            long x = Long.parseLong(m.group(1));
            long y = Long.parseLong(m.group(2));
            str = str.replaceFirst(subStr, 4 * x + 3 * y + 2 + "");
        }
    
        long result = Arrays.stream(str.split("\\$"))
            .map(Long::parseLong)
            .reduce((x, y) -> 2 * x + y + 3)
            .orElse(0L);

         System.out.println(result);
    }

    private static void doStack(String str){


    }
}
